<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>深拷贝和浅拷贝</title>
</head>

<body>
    <!-- <script>
        let a = 3
        let b = a
        b = 4
        console.log(a, b) // 3, 4
        /**
         * 说明：- 上面操作为赋值，严格意义上来讲不存在拷贝的概念
         *          - 如果一定要说是哪一种拷贝的话，那么是属于深拷贝的
         *              - 因为b的值发生改变时，不影响a的值
         */

        let arr = [1, 2, 3, 4]
        let newArr = arr
        newArr.push(5)
        console.log(arr, newArr) // [1, 2, 3, 4, 5]  [1, 2, 3, 4, 5]
        /**
         * 说明：- 上面操作属于浅拷贝
         *          - 因为当newArr的值发生改变时，arr的值也发生了改变
         */


        let arr1 = [1, 2, 3, 4]
        let newArr1 = [...arr1]
        newArr1.push(5)
        console.log(arr1, newArr1) // [1, 2, 3, 4]  [1, 2, 3, 4, 5]
        /**
         * 说明：-上面解构的操作属于深拷贝
         *          - 因为newArr1的值发生改变时，arr1的值没有发生改变
         *      - 但是该结论并不能说明解构操作就是深拷贝
         *          - 因为当对象有多层嵌套时，新对象的改变也会影响老对象的值得改变
         */

        let arr2 = [
            [1, 2],
            [3, 4]
        ]
        let newArr2 = [...arr2]
        newArr2[0].push(5)
        console.log(arr2, newArr2)
        /**
         * 说明：-上面解构的操作属于浅拷贝
         *          - 因为newArr2的值发生改变时，arr2的值也发生改变
         *          - 所以当对象有多层嵌套时，新对象的改变也会影响老对象的值得改变
         */

        /**
         * 如何实现一个深拷贝呢？
         */

        function deepClone(obj) {
            let newObj = obj.constructor === Array ? [] : {}
            for (let key in obj) {
                if (obj.hasOwnProperty(key)) {
                    // 如果值为引用类型
                    if (obj[key] && typeof obj[key] === 'object') {
                        // 给新对象分配内存空间 (可省略，最好有，相当于维护代码)
                        newObj[key] = obj[key].constructor === Array ? [] : {}
                        // 递归拷贝
                        newObj[key] = deepClone(obj[key])
                    } else {
                        // 如果非引用类型，直接赋值
                        newObj[key] = obj[key]
                    }
                }
            }
            return newObj
        }

        /**
         * 深拷贝
         * @param {Object} obj 要拷贝的对象
         * @param {Map} map 用于存储循环引用对象的地址
         */

        //  function deepClone(obj = {}, map = new Map()) {
        //     if (typeof obj !== "object") {
        //         return obj;
        //     }
        //     if (map.get(obj)) {
        //         return map.get(obj);
        //     }

        //     let result = {};
        //     // 初始化返回结果
        //     if (
        //         obj instanceof Array ||
        //         // 加 || 的原因是为了防止 Array 的 prototype 被重写，Array.isArray 也是如此
        //         Object.prototype.toString(obj) === "[object Array]"
        //     ) {
        //         result = [];
        //     }
        //     // 防止循环引用
        //     map.set(obj, result);
        //     for (const key in obj) {
        //         // 保证 key 不是原型属性
        //         if (obj.hasOwnProperty(key)) {
        //             // 递归调用
        //             result[key] = deepClone(obj[key], map);
        //         }
        //     }

        //     // 返回结果
        //     return result;
        // }


        let obj = {
            a: 1,
            arr: [1, 2, 3],
            o: {
                c: 2,
                d: 's'
            }
        }
        let newObj = deepClone(obj)
        newObj.a = 11
        newObj.arr.push(4)
        newObj.o.c = 22
        console.log(obj, newObj)

    </script>

    <script type="module">
        // open with live server
        import {deepClone} from './js/01_DeepClone/DeepClone1.js'
        let obj1 = {
            a: 1,
            arr: [1, 2, 3],
            o: {
                c: 2,
                d: 's'
            }
        }
        let newObj1 = deepClone(obj1)
        newObj1.a = 11
        newObj1.arr.push(4)
        newObj1.o.c = 22
        console.log(obj1, newObj1)
    </script> -->

    <!-- 第2次手写 -->
    <!-- <script src="./js/01_DeepClone/DeepClone2.js"></script> -->

    <!-- 第3次手写 -->
    <!-- <script src="./js/01_DeepClone/DeepClone3.js"></script> -->

    <script type="module">
        // 第4次手写
        // import {deepClone} from './js/01_DeepClone/DeepClone4.js'

        // 第5次手写
        // import {deepClone} from './js/01_DeepClone/DeepClone5.js'

        // 第6次手写
        // import {deepClone} from './js/01_DeepClone/DeepClone6.js'

        // 第7次手写
        // import {deepClone} from './js/01_DeepClone/DeepClone7.js'

        // 第8次手写
        // import deepClone from './js/01_DeepClone/DeepClone8.js'

        // 第10次手写
        // import deepClone from './js/01_DeepClone/DeepClone10.js'

        // 第12次手写
        import deepClone from './js/01_DeepClone/DeepClone12.js'

        let obj = {
            a: 1,
            arr: [1, 2, 3],
            o: {
                c: 2,
                d: 's'
            }
        }
        let newObj = deepClone(obj)
        newObj.a = 11
        newObj.arr.push(4)
        newObj.o.c = 22
        console.log(obj, newObj)
    </script>
</body>

</html>